如果我有一個小貓類別,我想要這個小貓類別有飛行功能,你會怎麼做?
直接寫一個有飛行功能的小鳥類別,然後再叫小貓類別去繼承它?
直接把飛行功能寫在小貓類別裡?
「繼承」的概念是:
我只要讓小貓類別去繼承小鳥類別就好啦,反正小鳥會飛,所以繼承之後的小貓就會飛了!
但第 1 種做法的設計有點怪怪的,好好的貓不當,為什麼要去當鳥?為了想要有飛行功能就去當別人家的小孩。第 2 種做法看來似乎可行,但如果之後又有「我希望我的這個小狗類別也會飛!」的需求,那這樣又得在小狗類別裡寫一段飛行功能,飛行功能的程式碼沒辦法共用。
這時候,模組就可以派上用場了。
飛行模組
在 Ruby 定義模組,使用的是 module 這個關鍵字:
module Flyable
def fly
puts "I can fly!"
end
end
寫起來的手感跟類別一樣,連模組名字的規定也跟類別一樣,必須是常數(也就是大字英文字母開頭)。模組定義好了之後,如果要把它拿來用,只要用 include 這個方法:
class Cat
include Flyable
end
kitty = Cat.new
kitty.fly # => I can fly!
把這個飛行模組掛上去,然後小貓就會飛了!之後如果小狗類別也想要有飛行功能的話,只要這樣一行:
class Dog
include Flyable
end
小狗也會飛了。
類別跟模組寫起來好像?
如果你注意到,在寫類別或模組的時候,除了一個是用 class,另一個是用 module,其它幾乎沒什麼差別。事實上,在 Ruby 裡,「類別」的上層類別就是「模組」,開 IRB 實驗一下:
$ irb
>> Class.superclass
=> Module
既然類別跟模組之間是繼承關係,讓我們來看看這兩個類別之間的差別:
$ irb
>> Class.instance_methods - Module.instance_methods
=> [:new, :allocate, :superclass]
可以發現身為「後代」的 Class 類別,比 Module 類別多了 3 個方法,就是因為 Module 類別少了這 3 個方法,所以它跟 Class 最大的差別,就是:
模組沒辦法 new 一個新的實體出來。
模組沒辦法繼承別的模組。
除此之外,模組跟類別在本質上沒什麼太大的差別。
要用繼承還是要用模組?
如果你發現你要做的這個功能,它可能在很多不同體系的類別裡都會用得到,那你可以考慮把功能寫在模組裡,需要的時候再 include 進來即可。但如果你還是不知道到底類別跟模組有什麼差別,我再舉二個例子。
不知道大家有沒看過火影忍者這部漫畫,漫畫裡的主人公之一,宇智波佐助,因為他們家族血統的關係,他寫輪眼這個功能是天生就有的,你可以想像他這個功能算是從他的家族「繼承」來的。而佐助的老師,旗木卡卡西,他雖然也有寫輪眼功能,但他的寫輪眼並非繼承來的,事實上是他在年輕時候 include 了某位朋友的寫輪眼模組,所以才有這個效果。
另一個例子,海賊王漫畫裡,主角魯夫本來是普通人,但在偶然的機會下,他 include 了橡膠果實之後,他就有了橡膠人的能力了,並不是因為他老爸是橡膠人所以他才是橡膠人。
[為你自己學Ruby on Rails]https://railsbook.tw/chapters/08-ruby-basic-4.html